package org.wyn.flowable.controller;


import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/process")
public class ProcessController {

    private static final Logger log = LoggerFactory.getLogger(ProcessController.class);

    private RuntimeService runtimeService;

    private HistoryService historyService;

    private TaskService taskService;

    private RepositoryService repositoryService;

    private IdentityService identityService;

    @Autowired
    public void setRuntimeService(RuntimeService runtimeService) {
        this.runtimeService = runtimeService;
    }

    @Autowired
    public void setTaskService(TaskService taskService) {
        this.taskService = taskService;
    }

    @Autowired
    public void setRepositoryService(RepositoryService repositoryService) {
        this.repositoryService = repositoryService;
    }

    @Autowired
    public void setIdentityService(IdentityService identityService) {
        this.identityService = identityService;
    }

    @Autowired
    public void setHistoryService(HistoryService historyService) {
        this.historyService = historyService;
    }


    /**
     * 3.启动流程
     * @param userId //标注id
     * @param processDefinitionKey 流程定义的key
     * @param businessKey 业务代码，根据自己的业务用
     * @param variables 流程变量，可以自定义扩充
     * @return
     */
    @PostMapping("/start")
    @Transactional(rollbackFor = Exception.class)
    public Object start(@RequestParam("userId") String userId,
                            @RequestParam("key") String processDefinitionKey,
                            @RequestParam("businessKey") String businessKey,
                            @RequestBody Map<String, Object> variables) {
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .latestVersion()
                .singleResult();

        if (definition == null) {
            return "流程定义未找到或者无开启权限";
        }
        try {
            identityService.setAuthenticatedUserId(userId);
            ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables);
            return (Object) instance.getId();
        } catch (Exception e) {
            log.error("流程开启异常", e);
            return "流程开启异常";
        }
    }

    /**
     * 4.查询指定流程所有启动的实例列表
     * @param processDefinitionKey 流程定义的key
     * @return
     */
    @GetMapping("/{processDefinitionKey}/example")
    public List<Execution> getExample(@PathVariable String processDefinitionKey) {
        List<Execution> executions = runtimeService.createExecutionQuery().processDefinitionKey(processDefinitionKey).list();
        List<Execution> executionPages = runtimeService.createExecutionQuery().processDefinitionKey(processDefinitionKey).listPage(1, 30);
//        runtimeService.deleteProcessInstance(processInstanceId, deleteReason); //删除实例
        return executions;
    }

    /**
     * 5.推进流程，查询可以操作的任务,并完成任务
     * @param userId
     * @param groups 候选组 xml文件里面的 flowable:candidateGroups="stu_group"
     * @param processInstanceId
     * @param variables
     * @return
     */
    @PutMapping("/complete")
    @Transactional(rollbackFor = Exception.class)
    public String complete(@RequestParam("userId") String userId,
                               @RequestParam("groups") List<String> groups,
                               @RequestParam("processInstanceId") String processInstanceId,
                               @RequestBody Map<String, Object> variables) {
        List<Task> list = getTasks(groups, processInstanceId);
        if (CollectionUtils.isEmpty(list)) {
            return "任务不存在或者无操作权限";
        }

        identityService.setAuthenticatedUserId(userId);
        list.stream()
                .map(TaskInfo::getId)
                .forEach(taskId -> taskService.complete(taskId, variables));
        return "ok";
    }
    public List<Task> getTasks(List<String> groups,
                               String processInstanceId) {
        List<Task> list = new ArrayList<>();

        list.addAll(taskService.createTaskQuery()
                .taskCandidateGroupIn(groups)
                .processInstanceId(processInstanceId)
                .list());

        return list;
    }

    /**
     * 6.中止流程
     * @param groups
     * @param processInstanceId
     * @param reason
     * @return
     */
    @PostMapping("/stop")
    @Transactional(rollbackFor = Exception.class)
    public String stop(@RequestParam List<String> groups,
                       @RequestParam String processInstanceId,
                       @RequestParam(required = false) String reason) {
        List<Task> list = getTasks(groups, processInstanceId);
        if (CollectionUtils.isEmpty(list)) {
            return "任务不存在或者无操作权限";
        }
        runtimeService.deleteProcessInstance(processInstanceId, reason);
        return "OK";
    }


    /**
     * 7.删除流程,单个processInstanceId
     * @param userId
     * @param processInstanceId
     * @param reason
     * @return
     */
    @PostMapping("/delete")
    @Transactional(rollbackFor = Exception.class)
    public String delete(@RequestParam String userId,
                             @RequestParam String processInstanceId,
                             @RequestParam(required = false) String reason) {
        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .startedBy(userId)
                .singleResult();
        if (instance == null) {
            return"流程实例不存在或者无操作权限";
        }

        runtimeService.deleteProcessInstance(processInstanceId, reason);
        return "OK";
    }

    /**
     * 7.删除流程,多个processInstanceId
     * @param userId
     * @param processInstanceIdList
     * @param reason
     * @return
     */
    @PostMapping("/delete/batch")
    @Transactional(rollbackFor = Exception.class)
    public String batchDelete(@RequestParam String userId,
                                  @RequestParam List<String> processInstanceIdList,
                                  @RequestParam(required = false) String reason) {
        processInstanceIdList.forEach(processInstanceId -> {
            ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .startedBy(userId)
                    .singleResult();
            if (instance == null) {
                throw new RuntimeException("流程实例不存在或者无操作权限");
            }

            runtimeService.deleteProcessInstance(processInstanceId, reason);
        });

        return "OK";
    }

    /**
     * 8.查询流程状态
     * @param processInstanceId
     * @return
     */
    @GetMapping("/{processInstanceId}/status")
    public String status(@PathVariable String processInstanceId) {
        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        if (instance == null) {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .finished()
                    .singleResult();
            if (historicProcessInstance != null) {
                return  "已办结";
            }

            return "流程实例未找到";
        }

        if (instance.isEnded()) {
            return "已办结";
        }

        List<Task> list = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .list();
        if (CollectionUtils.isEmpty(list)) {
            return "未找到任务节点";
        }

        return list.stream().map(TaskInfo::getName).collect(Collectors.joining("/"));
    }

    /**
     * 9.获取当前任务对应流程实例集合
     * @param groups
     * @param keyLike
     * @return
     */
    @PostMapping("/list")
    @Transactional(rollbackFor = Exception.class)
    public String start(@RequestParam List<String> groups,
                            @RequestParam String keyLike) {
        List<Task> tasks = getTasks2(groups, keyLike);

        Set<String> ids = new HashSet<>();
        Map<String, List<String>> statusMap = new HashMap<>();

        tasks.forEach(task -> {
            String taskId = task.getId();
            if (ids.contains(taskId)) {
                return;
            }

            ids.add(taskId);
            String processInstanceId = task.getProcessInstanceId();
            String status = task.getName();
            statusMap.computeIfAbsent(processInstanceId, s -> new ArrayList<>()).add(status);
        });

        return  "ok";
    }

    public List<Task> getTasks2(List<String> groups,
                                String keyLike) {
        List<Task> list = new ArrayList<>();

        list.addAll(taskService.createTaskQuery()
                .taskCandidateGroupIn(groups)
                .processDefinitionKeyLike(keyLike + "%")
                .list());

        return list;
    }
}
